package com.gzsxy.esjy.request;

import com.gzsxy.esjy.common.Assert;
import com.gzsxy.esjy.response.HttpServletResponse;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
 * 上下文支持
 * @author zhangxiaolong
 *
 */
public final class ContextHolder {

	private final static ThreadLocal<HttpServletRequest> HTTPSERVLETREQUEST = new ThreadLocal<HttpServletRequest>();
	
	private final static ThreadLocal<HttpServletResponse> HTTPSERVLETRESPONSE = new ThreadLocal<HttpServletResponse>();

	private final static ObjectFactoryDelegatingInvocationHandler REQUEST_HOLDER = new ObjectFactoryDelegatingInvocationHandler(new RequestObjectFactory()) ;
	
	private final static ObjectFactoryDelegatingInvocationHandler RESPONSE_HOLDER = new ObjectFactoryDelegatingInvocationHandler(new ResponseObjectFactory()) ;
	
	
	@SuppressWarnings("serial")
	private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
	    private final ObjectFactory<?> objectFactory;

	    public ObjectFactoryDelegatingInvocationHandler (ObjectFactory<?> objectFactory) {
	        this.objectFactory = objectFactory;
	    }

	    @Override
	    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	        try {
	            return method.invoke(this.objectFactory.getObject(), args); 
	        }
	        catch (InvocationTargetException ex) {
	            throw ex.getTargetException();
	        }
	    }
	}
	
	@SuppressWarnings("serial")
	private static class RequestObjectFactory implements ObjectFactory<HttpServletRequest>, Serializable {
	    @Override
	    public HttpServletRequest getObject() {
	        return HTTPSERVLETREQUEST.get() ;
	    }
	    @Override
	    public String toString() {
	        return "Current HttpServletRequest";
	    }
	}
	
	@SuppressWarnings("serial")
	private static class ResponseObjectFactory implements ObjectFactory<HttpServletResponse>, Serializable {
		@Override
		public HttpServletResponse getObject() {
			return HTTPSERVLETRESPONSE.get();
		}
		@Override
		public String toString() {
			return "Current httpServletResponse";
		}
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T getContextHolderProxy(Class<T> mapperInterface) {
		ClassLoader classLoader = mapperInterface.getClassLoader();  
		Class<?>[] interfaces = new Class[]{mapperInterface};  
		if(mapperInterface == HttpServletRequest.class) {
			return (T) Proxy.newProxyInstance(classLoader, interfaces,REQUEST_HOLDER);
		}
		Assert.notTrue(mapperInterface == HttpServletResponse.class, "proxy HttpServletResponse error");
		return (T) Proxy.newProxyInstance(classLoader, interfaces,RESPONSE_HOLDER);
	}
	
	/**
	 * 存入request
	 * @param request
	 */
	public static void putRequest(HttpServletRequest request) {
		HTTPSERVLETREQUEST.set(request);
	}
	
	/**
	 * 放置response
	 * @param request
	 */
	public static void putResponse(HttpServletResponse request) {
		HTTPSERVLETRESPONSE.set(request);
	}
	
	/**
	 * 移除
	 */
	public static void remove() {
		HTTPSERVLETRESPONSE.remove();
		HTTPSERVLETREQUEST.remove();
	}
}